﻿// -----------------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
// -----------------------------------------------------------------------
using System;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Primitives;
using System.Globalization;
using System.Reflection;
using Microsoft.Internal;

namespace System.ComponentModel.Composition.ReflectionModel
{
    internal class ExportingMember
    {
        private readonly ExportDefinition _definition;
        private readonly ReflectionMember _member;

        public ExportingMember(ExportDefinition definition, ReflectionMember member)
        {
            Assumes.NotNull(definition, member);

            _definition = definition;
            _member = member;
        }

        public bool RequiresInstance
        {
            get { return _member.RequiresInstance; }
        }

        public ExportDefinition Definition
        {
            get { return _definition; }
        }

        public object GetExportedObject(object instance)
        {
            EnsureReadable();

            object exportedObject;
            Exception exception = ReflectionServices.InvokeWrappingInCatch(() => this._member.GetValue(instance), out exportedObject);
            if (exception != null)
            {   // Member threw an exception. Avoid letting this 
                // leak out as a 'raw' unhandled exception, instead,
                // we'll add some context and rethrow.

                throw new ComposablePartException(
                    CompositionErrorId.ReflectionModel_ExportThrewException,
                    String.Format(CultureInfo.CurrentCulture, 
                        Strings.ReflectionModel_ExportThrewException,
                        this._member.DisplayName),
                    Definition.ToElement(),
                    exception);
            }

            return exportedObject;
        }

        private void EnsureReadable()
        {
            if (!this._member.CanRead)
            {   // Property does not have a getter

                throw new ComposablePartException(
                    CompositionErrorId.ReflectionModel_ExportNotReadable,
                    String.Format(CultureInfo.CurrentCulture, 
                        Strings.ReflectionModel_ExportNotReadable,
                        this._member.DisplayName),
                    Definition.ToElement());
            }

            if (this._member.ItemType == ReflectionItemType.Method)
            {
                MethodInfo method = (MethodInfo)this._member.UnderlyingMember;
                int parameterCount = method.GetParameters().Length;
                if (parameterCount > 4)
                {   // Action and Func delegates only support 4 parameters

                    throw new ComposablePartException(
                        CompositionErrorId.ReflectionModel_ExportMethodTooManyParameters,
                        String.Format(CultureInfo.CurrentCulture,
                            Strings.ReflectionModel_ExportMethodTooManyParameters,
                            this._member.DisplayName,
                            parameterCount),
                        Definition.ToElement());
                }
            }
        }
    }
}
